package com.sanron.sunweather.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;

import com.sanron.sunweather.R;

/**
 * 旋转的地球视图
 * @author 三荣君
 *
 */
public class RotateView extends View{

	private final float ROTATE_SPEED = 2;//每秒转动角度;
	private final float NORMAL_OFF_DEGREES = ROTATE_SPEED/100;
	private final int ANIMATION_DURATION = 400;//动画时间

	public static int STATE_UP = 1;
	public static int STATE_DOWN = 2;
	public static int STATE_HIDE = 3;
	
	private Bitmap earth;
	private Scroller scroller;
	/*** 当前选择角度*/
	private float currentDegrees = 0;
	private FlingRotateTask flingRotateTask;//快速旋转
	private GestureDetector detector;//手势解析
	private boolean touchRotateable = true;//是否可触摸转动
	private int scrollMin = -1;//scrollY最小值
	private int scrollMax = 0;//scrollY最大值
	private int state = STATE_UP;
	private boolean isDrag = false;
	private float offDegrees = NORMAL_OFF_DEGREES; //角度偏移
	private OnSingleTapListener onSingleTapListener;//单击
	private OnScrollListener onScrollListener;
	private OnStateChangeListener onStateChangeListener;
	
	
	public RotateView(Context context, AttributeSet attrs) {
		super(context, attrs);
		scroller = new Scroller(getContext());
		detector = new GestureDetector(getContext(),new OnGestureListener() {
			@Override
			public boolean onSingleTapUp(MotionEvent e) {
				if(state == STATE_UP){
					toDown(true);
				}else if(state == STATE_DOWN){
					toUp(true);
				}
				if(onSingleTapListener!=null){
					onSingleTapListener.onSingleTap(RotateView.this);
				}
				return true;
			}
			
			@Override
			public void onShowPress(MotionEvent e) {
			}
			
			@Override
			public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
					float distanceY) {
				isDrag = true;
				if( Math.abs(distanceX) > Math.abs(distanceY)){
					if(touchRotateable){
						offDegrees = (float) ((-distanceX)/10);
						postInvalidate();
					}
				}else{
					int toY = (int) (getScrollY()+distanceY);
					if(toY<scrollMin){
						scrollTo(0, scrollMin);
					}else if(toY>scrollMax){
						scrollTo(0, scrollMax);
					}else{
						scrollTo(0, toY);
					}
				}
				return true;
			}
			
			@Override
			public void onLongPress(MotionEvent e) {
			}
			
			@Override
			public boolean onFling(MotionEvent e1, MotionEvent e2, final float velocityX,
					float velocityY) {
				//飞速旋转
				if(touchRotateable){
					flingRotateTask = new FlingRotateTask();
					flingRotateTask.start(velocityX/2500);
				}
				return true;
			}
			
			@Override
			public boolean onDown(MotionEvent e) {
				//判断是否在地球内触摸
				isDrag = false;
				int x = (int) e.getX();
				int y = (int) e.getY();
				int dx = x-getWidth()/2;
				int dy = (y+getScrollY())-getHeight();
				
				if(Math.sqrt(dx*dx+dy*dy) < earth.getWidth()*0.4){
					//按下时停止所有旋转
					offDegrees = 0;
					return true;
				}
				return false;
			}
			
		});
	}
	
	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		if(scrollMin == -1){
			//计算scrollY最小值
			scrollMin = (int) (-getMeasuredHeight()*0.5);
		}
		if(earth==null){
			//加载位图
			Bitmap origin = BitmapFactory.decodeResource(getResources(), R.drawable.earth);
			earth = Bitmap.createScaledBitmap(origin, getMeasuredHeight()*2, getMeasuredHeight()*2,true);
			origin.recycle();
			System.gc();
		}
		super.onLayout(changed, left, top, right, bottom);
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		canvas.rotate(currentDegrees,getWidth()/2, getHeight());
		canvas.translate(getWidth()/2-earth.getWidth()/2, 0);
		canvas.drawBitmap(earth,0,0,null);
		currentDegrees += offDegrees;
		if(currentDegrees > 360 || currentDegrees < -360){
			currentDegrees = currentDegrees*1000%360000/1000f;
		}
		if(offDegrees!=0){
			postInvalidateDelayed(10);
		}
	}
	
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if(event.getAction() == MotionEvent.ACTION_UP
				|| event.getAction()==MotionEvent.ACTION_CANCEL){
			
			if(isDrag){
				if(getScrollY()<(scrollMin)/2){
					toDown(true);
				}else{
					toUp(true);
				}
			}
			offDegrees = NORMAL_OFF_DEGREES;
			postInvalidate();
		}
		return detector.onTouchEvent(event);
	}

	
	@Override
	public void computeScroll() {
		if(scroller.computeScrollOffset()){
			int toY = scroller.getCurrY();
			scrollTo(0, toY);
			invalidate();
		}
	}
	
	@Override
	protected void onScrollChanged(int l, int t, int oldl, int oldt) {
		super.onScrollChanged(l, t, oldl, oldt);
		if(onScrollListener!=null){
			onScrollListener.onScroll(t-oldt);
		}
	}

	private void toUp(boolean isActively){
		scroller.startScroll(0, getScrollY(), 0, -getScrollY(),ANIMATION_DURATION);
		invalidate();
		if(state != STATE_UP){
			if(isActively && onStateChangeListener!=null){
				onStateChangeListener.onStateChange(STATE_UP, state);
			}
			state = STATE_UP;
		}
		setTouchRotateable(true);
	}
	
	/**
	 * 向下弹出
	 * @param isActively是否触发状态改变事件
	 */
	private void toDown(boolean isActively){
		scroller.startScroll(0, getScrollY(), 0, scrollMin-getScrollY(),ANIMATION_DURATION);
		invalidate();
		if(state != STATE_DOWN){
			if(isActively && onStateChangeListener!=null){
				onStateChangeListener.onStateChange(STATE_DOWN, state);
			}
			state = STATE_DOWN;
		}
		setTouchRotateable(false);
	}
	
	/**
	 * 向下隐藏
	 */
	private void toHide(boolean isActively){
		scroller.startScroll(0, getScrollY(), 0, -getMeasuredHeight()-getScrollY(),ANIMATION_DURATION);
		invalidate();
		if(state != STATE_HIDE){
			if(isActively && onStateChangeListener!=null){
				onStateChangeListener.onStateChange(STATE_HIDE, state);
			}
			state = STATE_HIDE;
		}
		setTouchRotateable(false);
	}

	public void toUp(){
		toUp(false);
	}
	
	public void toDown(){
		toDown(false);
	}
	
	public void toHide(){
		toHide(false);
	}
	
	

	/**
	 * 单击事件监听（按下与抬起的位置相投，即手指未滑动）
	 * @author Administrator
	 *
	 */
	public interface OnSingleTapListener{
		public void onSingleTap(View v);
	}
	
	public void setOnSingleTapListener(OnSingleTapListener onSingleTapListener) {
		this.onSingleTapListener = onSingleTapListener;
	}

	public boolean isTouchRotateable() {
		return touchRotateable;
	}

	public void setTouchRotateable(boolean touchRotateable) {
		this.touchRotateable = touchRotateable;
	}

	
	
	public OnStateChangeListener getOnStateChangeListener() {
		return onStateChangeListener;
	}

	public void setOnStateChangeListener(OnStateChangeListener onStateChangeListener) {
		this.onStateChangeListener = onStateChangeListener;
	}

	public OnScrollListener getOnScrollListener() {
		return onScrollListener;
	}

	public void setOnScrollListener(OnScrollListener onScrollListener) {
		this.onScrollListener = onScrollListener;
	}

	


	/**
	 * 快速旋转
	 * @author Administrator
	 *
	 */
	public class FlingRotateTask extends Thread{
		
		public void start(float velocityX){
			offDegrees = velocityX;
			super.start();
		}
		public void stopFling(){
			offDegrees = 0;
		}
		@Override
		public void run() {
			//加速度
			float factor = 0.01f;
			if(offDegrees>0){
				while(offDegrees>0){
					offDegrees -= factor;
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}else if(offDegrees<0){
				while(offDegrees<0){
					offDegrees += factor;
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			offDegrees = NORMAL_OFF_DEGREES;
		}
	}
	
	
	public interface OnScrollListener{
		/**
		 * 
		 * @param offY y轴位移
		 */
		public void onScroll(int offY);
	}
	
	public interface OnStateChangeListener{
		public void onStateChange(int state,int oldState);
	}
}
